/**
 * 下面是实现ai的具体步骤
 **/
var Falg = {
    empty: 0, hum: 1, com: 2, nor: 0, win: 1, reverse: function (r) {
        return r === 1 ? 2 : 1;
    }
};//* 人的角色为1,电脑角色为2,普通棋子为0,胜利棋子为1,附带一个角色取反函数 */
var Config = {
    searchDeep: 7,  //搜索深度
    deepDecrease: .8, //按搜索深度递减分数，为了让短路径的结果比深路劲的分数高
    countLimit: 9, //gen函数返回的节点数量上限，超过之后将会按照分数进行截断
    checkmateDeep: 6,  //算杀深度
    cache: true  //是否使用效率不高的置换表
};
/*
 * 棋型表示
 * 用一个6位数表示棋型，从高位到低位分别表示
 * 连五，活四，眠四，活三，活二/眠三，活一/眠二, 眠一
 */
var score = {
    ONE: 10,
    TWO: 100,
    THREE: 1000,
    FOUR: 100000,
    FIVE: 1000000,
    BLOCKED_ONE: 1,
    BLOCKED_TWO: 10,
    BLOCKED_THREE: 100,
    BLOCKED_FOUR: 10000
};
var Gomoku = function () { //* 定义Gomoku对象 */
};
var gomoku = new Gomoku();  //* 实例化对象 */
/**
 * 使用workers的方法,将参数传递给算法
 * @param e
 */
onmessage = function (e) { //* 处理下棋的请求 */
    var d = e.data;
    if (d.type === 'start') { //* 初始化数据 */
        gomoku.init(d.size);
    } else if (d.type === 'go') { //* 执行运算 */
        gomoku.put([d.x, d.y], Falg.hum); // 玩家落子
        var haveWinPos = gomoku.isWin(d.x, d.y, Falg.hum);
        if (haveWinPos !== null) {
            postMessage({winRole: Falg.hum, winPos: haveWinPos});
            return;
        }

        var p = deeping(Config.searchDeep);
        gomoku.put(p, Falg.com); // 电脑落子

        haveWinPos = gomoku.isWin(p[0], p[1], Falg.com);
        if (haveWinPos !== null) {
            postMessage({winRole: Falg.com, winPos: haveWinPos});
            return;
        }
        postMessage({pos: p, winRole: Falg.empty}); // 没有胜利则提示ui画黑色电脑棋子
    }
};
//初始化数据
Gomoku.prototype.init = function (size) {
    var i, j;
    this.board = new Array(size);//初始化棋盘
    this.evaluateCache = {}; // 估分缓存函数
    this.zobrist = new Zobrist(size);//得到Zobrist对象
    this.comScore = [];//初始化电脑分数
    this.humScore = [];//初始化人的分数
    for (i = 0; i < size; i++) {
        this.board[i] = new Array(size);
        this.comScore[i] = new Array(size);
        this.humScore[i] = new Array(size);

        for (j = 0; j < size; j++) {
            this.board[i][j] = Falg.empty;
        }
    }
    i = parseInt(size / 2); // 电脑先手,占据棋盘最中间
    this.board[i][i] = Falg.com;
    this.zobrist.go(i, i, Falg.com); // zobrist的hash打分
    postMessage({pos: [i, i], winRole: Falg.empty}); // 让页面正中间画黑棋

    var board = this.board; // 使用缓存的变量初始化数据
    for (i = 0; i < size; i++) {
        for (j = 0; j < size; j++) {
            if (board[i][j] === Falg.empty) {
                if (hasNeighbor(board, [i, j], 2, 2)) { //必须是有邻居的才行
                    var cs = scorePoint(board, [i, j], Falg.com);
                    var hs = scorePoint(board, [i, j], Falg.hum);
                    this.comScore[i][j] = cs;
                    this.humScore[i][j] = hs;
                }
            }
        }
    }
};
//只更新一个点附近的分数
Gomoku.prototype.updateScore = function (p) {
    var i, x, y, radius = 8, board = this.board, self = this, len = this.board.length;

    function update(x, y) {
        var cs = scorePoint(board, [x, y], Falg.com);
        var hs = scorePoint(board, [x, y], Falg.hum);
        self.comScore[x][y] = cs;
        self.humScore[x][y] = hs;
        //注意下面这样写是错的！因为很可能最高分已经没了，不是总是取最高分的，这样分数会越来越高的。所以改成每次遍历计算
        /*self.comMaxScore = Math.max(cs, self.comMaxScore);
        self.humMaxScore = Math.max(hs, self.humMaxScore);*/
    }

    // -
    for (i = -radius; i < radius; i++) {
        x = p[0];
        y = p[1] + i;
        if (y < 0) continue;
        if (y >= len) break;
        if (board[x][y] !== Falg.empty) continue;
        update(x, y);
    }

    // |
    for (i = -radius; i < radius; i++) {
        x = p[0] + i;
        y = p[1];
        if (x < 0) continue;
        if (x >= len) break;
        if (board[x][y] !== Falg.empty) continue;
        update(x, y);
    }

    // \
    for (i = -radius; i < radius; i++) {
        x = p[0] + i;
        y = p[1] + i;
        if (x < 0 || y < 0) continue;
        if (x >= len || y >= len) break;
        if (board[x][y] !== Falg.empty) continue;
        update(x, y);
    }

    // /
    for (i = -radius; i < radius; i++) {
        x = p[0] + i;
        y = p[1] - i;
        if (x < 0 || y < 0) continue;
        if (x >= len || y >= len) continue;
        if (board[x][y] !== Falg.empty) continue;
        update(x, y);
    }
    //通过遍历来计算最高分
};
//下子
Gomoku.prototype.put = function (p, role) {
    this.board[p[0]][p[1]] = role;
    this.zobrist.go(p[0], p[1], role);
    this.updateScore(p);
};
//移除棋子
Gomoku.prototype.remove = function (p) {
    var r = this.board[p[0]][p[1]];
    this.zobrist.go(p[0], p[1], r);
    this.board[p[0]][p[1]] = Falg.empty;
    this.updateScore(p);
};
//启发函数
Gomoku.prototype.gen = function () {
    var fives = [];
    var fours = [];
    var blockedfours = [];
    var twothrees = [];
    var threes = [];
    var twos = [];
    var neighbors = [];

    var board = this.board;

    for (var i = 0; i < board.length; i++) {
        for (var j = 0; j < board[i].length; j++) {
            if (board[i][j] === Falg.empty) {
                if (hasNeighbor(board, [i, j], 2, 2)) { //必须是有邻居的才行
                    var scoreHum = this.humScore[i][j];
                    var scoreCom = this.comScore[i][j];
                    if (scoreCom >= score.FIVE) {//先看电脑能不能连成5
                        return [[i, j]];
                    } else if (scoreHum >= score.FIVE) {//再看玩家能不能连成5
                        //别急着返回，因为遍历还没完成，说不定电脑自己能成五。
                        fives.push([i, j]);
                    } else if (scoreCom >= score.FOUR) {
                        fours.unshift([i, j]);
                    } else if (scoreHum >= score.FOUR) {
                        fours.push([i, j]);
                    } else if (scoreCom >= score.BLOCKED_FOUR) {
                        blockedfours.unshift([i, j]);
                    } else if (scoreHum >= score.BLOCKED_FOUR) {
                        blockedfours.push([i, j]);
                    } else if (scoreCom >= 2 * score.THREE) {
                        //能成双三也行
                        twothrees.unshift([i, j]);
                    } else if (scoreHum >= 2 * score.THREE) {
                        twothrees.push([i, j]);
                    } else if (scoreCom >= score.THREE) {
                        threes.unshift([i, j]);
                    } else if (scoreHum >= score.THREE) {
                        threes.push([i, j]);
                    } else if (scoreCom >= score.TWO) {
                        twos.unshift([i, j]);
                    } else if (scoreHum >= score.TWO) {
                        twos.push([i, j]);
                    } else {
                        neighbors.push([i, j]);
                    }
                }
            }
        }
    }

    //如果成五，是必杀棋，直接返回
    if (fives.length) return [fives[0]];

    //注意一个活三可以有两个位置形成活四，但是不能只考虑其中一个，要从多个中考虑更好的选择
    //所以不能碰到活四就返回第一个，应该需要考虑多个
    if (fours.length) return fours;

    //冲四活三
    if (blockedfours.length) return [blockedfours[0]];

    //双三很特殊，因为能形成双三的不一定比一个活三强
    if (twothrees.length) {
        return twothrees.concat(threes);
    }

    var result = threes.concat(
        twos.concat(
            neighbors
        )
    );

    if (result.length > Config.countLimit) {
        return result.slice(0, Config.countLimit);
    }

    return result;
};
//棋面估分
Gomoku.prototype.evaluate = function (role) {
    //这里加了缓存，但是并没有提升速度
    if (this.evaluateCache[this.zobrist.code]) return this.evaluateCache[this.zobrist.code];
    this.comMaxScore = -score.FIVE;
    this.humMaxScore = -score.FIVE;

    var board = this.board;

    //遍历出最高分，开销不大
    for (var i = 0; i < board.length; i++) {
        for (var j = 0; j < board[i].length; j++) {
            if (board[i][j] === Falg.empty) {
                this.comMaxScore = Math.max(this.comScore[i][j], this.comMaxScore);
                this.humMaxScore = Math.max(this.humScore[i][j], this.humMaxScore);
            }
        }
    }
    var result = (role === Falg.com ? 1 : -1) * (this.comMaxScore - this.humMaxScore);
    this.evaluateCache[this.zobrist.code] = result;

    return result;

};
//* 判断x,y位置落子role角色后输赢情况,胜利就返回5个子的位置,失败返回null */
Gomoku.prototype.isWin = function (x, y, role) {
    var count = 0, i, j, len = this.board.length;
    var WinZi = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]; //* 保存胜利的五个子的位置 */
    //横向五子
    for (i = x; i >= 0; i--) {//横向向左
        if (this.board[i][y] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = i;
        WinZi[count][1] = y;
        count++;
    }
    for (i = x + 1; i < len; i++) {//横向向右
        if (this.board[i][y] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = i;
        WinZi[count][1] = y;
        count++;
    }
    if (count >= 5) {
        return WinZi;
    }
    //纵向五子
    for (count = 0, i = y; i >= 0; i--) {//纵向向上
        if (this.board[x][i] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = x;
        WinZi[count][1] = i;
        count++;
    }
    for (i = y + 1; i < len; i++) {//纵向向下
        if (this.board[x][i] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = x;
        WinZi[count][1] = i;
        count++;
    }
    if (count >= 5) {
        return WinZi;
    }
    //左上右下
    for (count = 0, i = x, j = y; (i >= 0) && (j >= 0); i--, j--) {
        if (this.board[i][j] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = i;
        WinZi[count][1] = j;
        count++;
    }
    for (i = x + 1, j = y + 1; (i < len) && (j < len); i++, j++) {
        if (this.board[i][j] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = i;
        WinZi[count][1] = j;
        count++;
    }
    if (count >= 5) {
        return WinZi;
    }
    //左下右上
    for (count = 0, i = x, j = y; (i >= 0) && (j < len); i--, j++) {
        if (this.board[i][j] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = i;
        WinZi[count][1] = j;
        count++;
    }
    for (i = x + 1, j = y - 1; (i < len) && (j >= 0); i++, j--) {
        if (this.board[i][j] !== role || count >= 5) {
            break;
        }
        WinZi[count][0] = i;
        WinZi[count][1] = j;
        count++;
    }

    return count >= 5 ? WinZi : null; //* 不满足胜利返回null */
};
//有邻居
var hasNeighbor = function (board, point, distance, count) {
    var i, j, len = board.length;
    var startX = point[0] - distance;
    var endX = point[0] + distance;
    var startY = point[1] - distance;
    var endY = point[1] + distance;
    for (i = startX; i <= endX; i++) {
        if (i < 0 || i >= len)
            continue;
        for (j = startY; j <= endY; j++) {
            if (j < 0 || j >= len)
                continue;
            if (i === point[0] && j === point[1])
                continue;
            if (board[i][j] !== Falg.empty) {
                count--;
                if (count <= 0)
                    return true;
            }
        }
    }
    return false;
};
//计算分数
var scorePoint = function (board, p, role) {
    var i, t, x, y, result = 0;
    var empty = 0, count = 0, block = 0, secondCount = 0;  //另一个方向的count
    var len = board.length;

    function reset() {
        count = 1;
        block = 0;
        empty = -1;
        secondCount = 0;  //另一个方向的count
    }

    reset();

    for (i = p[1] + 1; true; i++) {
        if (i >= len) {
            block++;
            break;
        }
        t = board[p[0]][i];
        if (t === Falg.empty) {
            if (empty === -1 && i < len - 1 && board[p[0]][i + 1] === role) {
                empty = count;
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            count++;
        } else {
            block++;
            break;
        }
    }


    for (i = p[1] - 1; true; i--) {
        if (i < 0) {
            block++;
            break;
        }
        t = board[p[0]][i];
        if (t === Falg.empty) {
            if (empty === -1 && i > 0 && board[p[0]][i - 1] === role) {
                empty = 0;  //注意这里是0，因为是从右往左走的
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            secondCount++;
            empty !== -1 && empty++;  //注意这里，如果左边又多了己方棋子，那么empty的位置就变大了
        } else {
            block++;
            break;
        }
    }

    count += secondCount;

    result += type(count, block, empty);

    //纵向
    reset();

    for (i = p[0] + 1; true; i++) {
        if (i >= len) {
            block++;
            break;
        }
        t = board[i][p[1]];
        if (t === Falg.empty) {
            if (empty === -1 && i < len - 1 && board[i + 1][p[1]] === role) {
                empty = count;
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            count++;
        } else {
            block++;
            break;
        }
    }

    for (i = p[0] - 1; true; i--) {
        if (i < 0) {
            block++;
            break;
        }
        t = board[i][p[1]];
        if (t === Falg.empty) {
            if (empty === -1 && i > 0 && board[i - 1][p[1]] === role) {
                empty = 0;
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            secondCount++;
            empty !== -1 && empty++;  //注意这里，如果左边又多了己方棋子，那么empty的位置就变大了
        } else {
            block++;
            break;
        }
    }

    count += secondCount;
    result += type(count, block, empty);

    // \\
    reset();

    for (i = 1; true; i++) {
        x = p[0] + i;
        y = p[1] + i;
        if (x >= len || y >= len) {
            block++;
            break;
        }
        t = board[x][y];
        if (t === Falg.empty) {
            if (empty === -1 && (x < len - 1 && y < len - 1) && board[x + 1][y + 1] === role) {
                empty = count;
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            count++;
        } else {
            block++;
            break;
        }
    }

    for (i = 1; true; i++) {
        x = p[0] - i;
        y = p[1] - i;
        if (x < 0 || y < 0) {
            block++;
            break;
        }
        t = board[x][y];
        if (t === Falg.empty) {
            if (empty === -1 && (x > 0 && y > 0) && board[x - 1][y - 1] === role) {
                empty = 0;
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            secondCount++;
            empty !== -1 && empty++;  //注意这里，如果左边又多了己方棋子，那么empty的位置就变大了
        } else {
            block++;
            break;
        }
    }

    count += secondCount;
    result += type(count, block, empty);

    // \/
    reset();

    for (i = 1; true; i++) {
        x = p[0] + i;
        y = p[1] - i;
        if (x < 0 || y < 0 || x >= len || y >= len) {
            block++;
            break;
        }
        t = board[x][y];
        if (t === Falg.empty) {
            if (empty === -1 && (x < len - 1 && y < len - 1) && board[x + 1][y - 1] === role) {
                empty = count;
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            count++;
        } else {
            block++;
            break;
        }
    }

    for (i = 1; true; i++) {
        x = p[0] - i;
        y = p[1] + i;
        if (x < 0 || y < 0 || x >= len || y >= len) {
            block++;
            break;
        }
        t = board[x][y];
        if (t === Falg.empty) {
            if (empty === -1 && (x > 0 && y > 0) && board[x - 1][y + 1] === role) {
                empty = 0;
                continue;
            } else {
                break;
            }
        }
        if (t === role) {
            secondCount++;
            empty !== -1 && empty++;  //注意这里，如果左边又多了己方棋子，那么empty的位置就变大了
        } else {
            block++;
            break;
        }
    }

    count += secondCount;
    result += type(count, block, empty);

    return typeToScore(result);
};
//判断棋型
var type = function (count, block, empty) {
    if (empty === undefined) empty = 0;

    //没有空位
    if (empty <= 0) {
        if (count >= 5) return score.FIVE;
        if (block === 0) {
            switch (count) {
                case 1:
                    return score.ONE;
                case 2:
                    return score.TWO;
                case 3:
                    return score.THREE;
                case 4:
                    return score.FOUR;
            }
        }

        if (block === 1) {
            switch (count) {
                case 1:
                    return score.BLOCKED_ONE;
                case 2:
                    return score.BLOCKED_TWO;
                case 3:
                    return score.BLOCKED_THREE;
                case 4:
                    return score.BLOCKED_FOUR;
            }
        }

    } else if (empty === 1 || empty === count - 1) {
        //第1个是空位
        if (count >= 6) {
            return score.FIVE;
        }
        if (block === 0) {
            switch (count) {
                case 2:
                    return score.TWO / 2;
                case 3:
                    return score.THREE;
                case 4:
                    return score.BLOCKED_FOUR;
                case 5:
                    return score.FOUR;
            }
        }

        if (block === 1) {
            switch (count) {
                case 2:
                    return score.BLOCKED_TWO;
                case 3:
                    return score.BLOCKED_THREE;
                case 4:
                    return score.BLOCKED_FOUR;
                case 5:
                    return score.BLOCKED_FOUR;
            }
        }
    } else if (empty === 2 || empty === count - 2) {
        //第二个是空位
        if (count >= 7) {
            return score.FIVE;
        }
        if (block === 0) {
            switch (count) {
                case 3:
                    return score.THREE;
                case 4:
                case 5:
                    return score.BLOCKED_FOUR;
                case 6:
                    return score.FOUR;
            }
        }

        if (block === 1) {
            switch (count) {
                case 3:
                    return score.BLOCKED_THREE;
                case 4:
                    return score.BLOCKED_FOUR;
                case 5:
                    return score.BLOCKED_FOUR;
                case 6:
                    return score.FOUR;
            }
        }

        if (block === 2) {
            switch (count) {
                case 4:
                case 5:
                case 6:
                    return score.BLOCKED_FOUR;
            }
        }
    } else if (empty === 3 || empty === count - 3) {
        if (count >= 8) {
            return score.FIVE;
        }
        if (block === 0) {
            switch (count) {
                case 4:
                case 5:
                    return score.THREE;
                case 6:
                    return score.BLOCKED_FOUR;
                case 7:
                    return score.FOUR;
            }
        }

        if (block === 1) {
            switch (count) {
                case 4:
                case 5:
                case 6:
                    return score.BLOCKED_FOUR;
                case 7:
                    return score.FOUR;
            }
        }

        if (block === 2) {
            switch (count) {
                case 4:
                case 5:
                case 6:
                case 7:
                    return score.BLOCKED_FOUR;
            }
        }
    } else if (empty === 4 || empty === count - 4) {
        if (count >= 9) {
            return score.FIVE;
        }
        if (block === 0) {
            switch (count) {
                case 5:
                case 6:
                case 7:
                case 8:
                    return score.FOUR;
            }
        }

        if (block === 1) {
            switch (count) {
                case 4:
                case 5:
                case 6:
                case 7:
                    return score.BLOCKED_FOUR;
                case 8:
                    return score.FOUR;
            }
        }

        if (block === 2) {
            switch (count) {
                case 5:
                case 6:
                case 7:
                case 8:
                    return score.BLOCKED_FOUR;
            }
        }
    } else if (empty === 5 || empty === count - 5) {
        return score.FIVE;
    }

    return 0;
};
/*
 * 只做一件事，就是修复冲四:
 * 如果是单独一个冲四，则将分数将至和活三一样
 * 如果是冲四活三或者双冲四，则分数和活四一样
 */
var typeToScore = function (type) {
    if (type < score.FOUR && type >= score.BLOCKED_FOUR) {

        if (type >= score.BLOCKED_FOUR && type < (score.BLOCKED_FOUR + score.THREE)) {
            //单独冲四，意义不大
            return score.THREE;
        } else if (type >= score.BLOCKED_FOUR + score.THREE && type < score.BLOCKED_FOUR * 2) {
            return score.FOUR;  //冲四活三，比双三分高，相当于自己形成活四
        } else {
            //双冲四 比活四分数也高
            return score.FOUR * 2;
        }
    }
    return type;
};

/**
 * Zobrist处理hash,速度快
 * @param size
 * @constructor
 */
var Zobrist = function (size) {
    this.size = size || 15;
    this.com = [];
    this.hum = [];

    function _rand() {
        return Math.floor(Math.random() * 1000000000);//再多一位就溢出了。。
    }

    for (var i = 0; i < this.size * this.size; i++) {
        this.com.push(_rand());
        this.hum.push(_rand());
    }

    this.code = _rand();
};
//
Zobrist.prototype.go = function (x, y, role) {
    var index = this.size * x + y;
    this.code ^= (role === Falg.com ? this.com[index] : this.hum[index]);
    return this.code;
};

//迭代加深算法
var deeping = function (deep) {
    deep = deep === undefined ? Config.searchDeep : deep;
    //迭代加深
    //注意这里不要比较分数的大小，因为深度越低算出来的分数越不靠谱，所以不能比较大小，而是是最高层的搜索分数为准
    var result;
    for (var i = 2; i <= deep; i += 2) {
        result = maxmin(i);
        if (math.greatOrEqualThan(result.score, score.FOUR)) return result;
    }
    return result;
};
var MAX = score.FIVE * 10;
var MIN = -1 * MAX;
var Cache = {};
var checkmateDeep = Config.checkmateDeep;
/*
 * max min search
 * white is max, black is min
 */
var maxmin = function (deep, _checkmateDeep) {
    var i, p, v, best = MIN;
    var points = gomoku.gen();
    var bestPoints = [];

    checkmateDeep = (_checkmateDeep === undefined ? checkmateDeep : _checkmateDeep);

    for (i = 0; i < points.length; i++) {
        p = points[i];
        gomoku.put(points[i], Falg.com);
        v = -max(deep - 1, -MAX, -best, Falg.hum);

        //边缘棋子的话，要把分数打折，避免电脑总喜欢往边上走
        if (p[0] < 3 || p[0] > 11 || p[1] < 3 || p[1] > 11) {
            v = .5 * v;
        }

        //如果跟之前的一个好，则把当前位子加入待选位子
        if (math.equal(v, best)) {
            bestPoints.push(p);
        }
        //找到一个更好的分，就把以前存的位子全部清除
        if (math.greatThan(v, best)) {
            best = v;
            bestPoints = [];
            bestPoints.push(p);
        }

        gomoku.remove(p);
    }
    // console.log("分数:" + best.toFixed(3) + ", 待选节点:" + JSON.stringify(bestPoints));
    var result = bestPoints[Math.floor(bestPoints.length * Math.random())];
    result.score = best;
    return result;
};

var max = function (deep, alpha, beta, role) {
    var i, v;
    if (Config.cache) {
        var c = Cache[gomoku.zobrist.code];
        if (c) {
            if (c.deep >= deep) {
                return c.score;
            }
        }
    }

    v = gomoku.evaluate(role);
    if (deep <= 0 || math.greatOrEqualThan(v, score.FIVE)) {
        return v;
    }

    var best = MIN;
    var points = gomoku.gen();

    for (i = 0; i < points.length; i++) {
        var p = points[i];
        gomoku.put(p, role);

        v = -max(deep - 1, -beta, -1 * ( best > alpha ? best : alpha), Falg.reverse(role)) * Config.deepDecrease;
        gomoku.remove(p);

        if (math.greatThan(v, best)) {
            best = v;
        }
        if (math.greatOrEqualThan(v, beta)) { //AB 剪枝
            cache(deep, v);
            return v;
        }
    }
    if ((deep === 2 || deep === 3 ) && math.littleThan(best, score.THREE * 2) && math.greatThan(best, score.THREE * -1)) {
        //var mate = checkmate(role, checkmateDeep);
        var mate = checkmateFast(gomoku.board, role, checkmateDeep);
        if (mate) {
            var t_score = mate.score * Math.pow(.8, mate.length) * (role === Falg.com ? 1 : -1);
            cache(deep, t_score);
            return t_score;
        }
    }
    cache(deep, best);

    return best;
};
var cache = function (deep, score) {
    if (!Config.cache) return;
    Cache[gomoku.zobrist.code] = {
        deep: deep,
        score: score
    };
};
//计算代码
var threshold = 1.1;
var math = {
    greatThan: function (a, b) {
        return a >= b * threshold;
    },
    greatOrEqualThan: function (a, b) {
        return a * threshold >= b;
    },
    littleThan: function (a, b) {
        return a * threshold <= b;
    },
    littleOrEqualThan: function (a, b) {
        return a <= b * threshold;
    },
    equal: function (a, b) {
        return (a * threshold >= b) && (a <= b * threshold);
    }
};
var MAX_SCORE = score.THREE;
var MIN_SCORE = score.FOUR;
var checkmateFast = function (board, role, deep, onlyFour) {
    deep = deep || Config.checkmateDeep;
    if (deep <= 0) return false;

    //先计算冲四赢的
    MAX_SCORE = score.FOUR;
    MIN_SCORE = score.FIVE;

    var result = deeping(board, role, deep);
    if (result) {
        result.score = score.FOUR;
        return result;
    }

    if (onlyFour) return false;  //只计算冲四

    //再计算通过 活三 赢的；
    MAX_SCORE = score.THREE;
    MIN_SCORE = score.FOUR;
    result = deeping(board, role, deep);
    if (result) {
        result.score = score.THREE * 2; //虽然不如活四分数高，但是还是比活三分数要高的
    }

    return result;

};
